package com.mehdiuz.backend.captcha.service.impl;

import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSONObject;
import com.mehdiuz.backend.captcha.entity.SliderCaptcha;
import com.mehdiuz.backend.captcha.service.CaptchaService;
import com.mehdiuz.backend.commons.utils.GaussianBlurUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.*;

@Service
public class CaptchaServiceImpl implements CaptchaService {

    private Integer threshold = 5;

    @Autowired
    private JedisPool jedisPool;

    /**
     * 从redis中获取原始图片的base64字符串
     * @return
     */
    @Override
    public SliderCaptcha getCaptcha() {
        Jedis jedis = jedisPool.getResource();
        SliderCaptcha sliderCaptcha = new SliderCaptcha();
        List<String> originalList = new ArrayList<>();
        List<String> sliderList = new ArrayList<>();
        try {
            String originalListString = jedis.get("originalImage");
            String sliderListString = jedis.get("sliderImage");
            originalList = JSONObject.parseArray(originalListString, String.class);
            sliderList = JSONObject.parseArray(sliderListString,String.class);
            int o = new Random().nextInt(originalList.size());
            int s = new Random().nextInt(sliderList.size());
            String originalImage = originalList.get(o);
            String sliderImage = sliderList.get(s);
            byte[] originalDecode = Base64.getDecoder().decode(originalImage);
            byte[] sliderDecode = Base64.getDecoder().decode(sliderImage);
            BufferedImage original = ImageIO.read(new ByteArrayInputStream(originalDecode));
            BufferedImage slider = ImageIO.read(new ByteArrayInputStream(sliderDecode));
            BufferedImage transparent = ImageIO.read(new ByteArrayInputStream(sliderDecode));

            int sliderWidth = slider.getWidth();
            int sliderHeight = slider.getHeight();
            int originalWidth = original.getWidth();
            int originalHeight = original.getHeight();
            int startX = sliderWidth;
            int endX = originalWidth - sliderWidth;
            int startY = sliderHeight;
            int endY = originalHeight - sliderHeight;
            int x = new Random().nextInt(endX - startX) + startX;
            int y = new Random().nextInt(endY - startY) + startY;
            BufferedImage image = original.getSubimage(x, y, sliderWidth, sliderHeight);

            for(int i = 0;i < sliderWidth;i++){
                for(int n = 0;n< sliderHeight;n++){
                    if(slider.getRGB(i,n)!=0){
                        slider.setRGB(i,n,image.getRGB(i,n));
                        transparent.setRGB(i,n,image.getRGB(i,n));
                    }
                }
            }

            int height = transparent.getHeight();
            int width = transparent.getWidth();
            int[][] martrix = new int[3][3];
            int[] values = new int[9];
            for (int i = 0; i < width; i++){
                for (int j = 0; j < height; j++) {
                    if(transparent.getRGB(i,j)!=0){
                        GaussianBlurUtil.readPixel(transparent, i, j, values);
                        GaussianBlurUtil.fillMatrix(martrix, values);
                        transparent.setRGB(i, j, GaussianBlurUtil.avgMatrix(martrix));
                    }
                }
            }

            for(int i = 0;i < sliderWidth;i++){
                for(int n = 0;n< sliderHeight;n++){
                    if(slider.getRGB(i,n)!=0){
                        original.setRGB(x+i,y+n,transparent.getRGB(i,n));
                    }
                }
            }

            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ImageIO.write(original,"png",byteArrayOutputStream);
            byte[] originalByte = byteArrayOutputStream.toByteArray();

            byteArrayOutputStream.reset();
            ImageIO.write(slider,"png",byteArrayOutputStream);
            byte[] sliderByte = byteArrayOutputStream.toByteArray();

            String originalEncode = Base64.getEncoder().encodeToString(originalByte);
            String sliderEncode = Base64.getEncoder().encodeToString(sliderByte);

            sliderCaptcha.setOriginalImage(originalEncode);
            sliderCaptcha.setSliderImage(sliderEncode);


            int targetX = x*400/originalWidth;
            int targetY = y*248/originalHeight;
            int[] target = new int[]{targetX,targetY};
            UUID uuid = UUID.fastUUID();
            String targetJson = JSONObject.toJSONString(target);
            jedis.set(uuid.toString(),targetJson);
            jedis.expire(uuid.toString(),30);

            sliderCaptcha.setUuid(uuid.toString());
            sliderCaptcha.setY(targetY);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            jedis.close();
        }
        return sliderCaptcha;
    }

    /**
     * 前端传回原始图片和滑块图片的base64值，存入redis中
     * @param captcha
     * @return
     */
    @Override
    public Boolean putCaptcha(List<SliderCaptcha> captcha) {
        if(captcha.isEmpty()){
            return false;
        }
        Jedis jedis = jedisPool.getResource();
        List<String> originalList = new ArrayList<>();
        List<String> sliderList = new ArrayList<>();
        String sliderImage = null;
        String originalImage = null;
        String originalListString = "";
        String sliderListString = "";
        try {
            originalListString = jedis.get("originalImage");
            sliderListString = jedis.get("sliderImage");
            if(null != originalListString){
                originalList = JSONObject.parseArray(originalListString, String.class);
            }
            if(null != sliderListString){
                sliderList = JSONObject.parseArray(sliderListString,String.class);
            }
            HashSet<String> originalSet = new HashSet<>(originalList);
            HashSet<String> sliderSet = new HashSet<>(sliderList);
            for (SliderCaptcha sliderCaptcha : captcha) {
                originalSet.add(sliderCaptcha.getOriginalImage());
                sliderSet.add(sliderCaptcha.getSliderImage());
            }
            originalList = new ArrayList<>(originalSet);
            sliderList = new ArrayList<>(sliderSet);

            originalListString = JSONObject.toJSONString(originalList);
            sliderListString = JSONObject.toJSONString(sliderList);
            originalImage = jedis.set("originalImage", originalListString);
            sliderImage = jedis.set("sliderImage", sliderListString);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            jedis.close();
        }
        if(sliderImage.isEmpty() || originalImage.isEmpty()){
            return false;
        }
        return true;
    }

    @Override
    public Boolean checkCaptcha(SliderCaptcha captcha) {
        Jedis jedis = jedisPool.getResource();
        Boolean res = false;
        try {
            String s = jedis.get(captcha.getUuid().toString());
            if(null == s){
                return false;
            }
            int[] target = JSONObject.parseObject(s, int[].class);
            int targetX = target[0];
            int targetY = target[1];
            if(Math.abs(captcha.getX() - targetX) <= threshold && captcha.getY() == targetY){
                res = true;
                jedis.del(captcha.getUuid().toString());
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            jedis.close();
        }
        return res;
    }
}
